/* 
 组件api说明
 1、依赖move.js，组件前一定要引入move.js
 2、轮播图需要有一个父级，这个父级一定要给一个id
*/

;(function(window, undefined){
	var Carousel = function(){
		this.settings = {
			id: 'pic',  //轮播图父级的id，必需传的参数
			autoplay: true,  //自动播放，true为自动， false为不自动，默认为true
			intervalTime: 1000,  //间隔时间，运动后停顿的时间，默认1s
			loop: true,  //循环播放，true为循环，false为不循环，默认为true
			totalNum: 5,  //图片总量
			moveNum: 1, //单次运动的图片数量（图片总量必须为运动数量的整倍数)
			circle: true,  //小圆点功能，true为显示，false为不显示，默认显示
			moveWay: 'opacity'  //运动方式,opacity为透明度过渡，position为位置过渡
		}
	}
	
	Carousel.prototype = {
		constructor: Carousel,
		init: function(opt){
			var opt = opt || this.settings
			
			for(var key in opt){  //用户设置 覆盖 默认设置
				this.settings[key] = opt[key]
			}
			
			this.createDom()
		},
		
		//创建左右切换按钮、指示圆点
		createDom: function(){
			var _this = this
			this.box = document.getElementById(this.settings.id)  //获取轮播图顶层容器
			
			//创建上一个按钮
			this.prevBtn = document.createElement("div")
			this.prevBtn.className = "prev"
			this.prevBtn.innerHTML = "<"
			this.prevBtn.onclick = function(){
				_this.prev()
				_this.trigger("leftBtnClick")
			}
			this.box.appendChild(this.prevBtn)
				
			//创建下一个按钮
			this.nextBtn = document.createElement("div")
			this.nextBtn.className = "next"
			this.nextBtn.innerHTML = ">"
			this.nextBtn.onclick = function(){
				_this.next()
				_this.trigger("rightBtnClick")
			}
			this.box.appendChild(this.nextBtn)
			
			//创建指示圆点
			this.circleWrap = document.createElement("div")  //圆点父容器
			this.circleWrap.className = "circle"
			this.circles = []  //存圆点，后面需要修改圆点的class，弄一个数组存起来会方便些
			for(var i=0; i<this.settings.totalNum/this.settings.moveNum; i++){
				var span = document.createElement("span")
				span.index = i
				span.onclick = function(){
					_this.cn = this.index
					_this[_this.settings.moveWay+"Move"]()
				}
				this.circles.push(span)
				this.circleWrap.appendChild(span)
			}
			this.circles[0].className = "active"
			if(this.settings.circle){
				this.box.appendChild(this.circleWrap)
			}
			
			this.moveInit()
		},
		
		//运动前的初始化 准备工作
		moveInit: function(){
			this.cn = 0  //当前的索引
			this.ln = 0  //上一个的索引
			this.canClick = true  //是否可以点击
			this.endNum = this.settings.totalNum/this.settings.moveNum  //停止条件
			
			this.opacityItem = this.box.children[0].children  //透明度变化 所有 运动项
			this.positionItemWrap = this.box.children[0].children[0]  //位置变化 运动项 父容器
			this.positionItem = this.positionItemWrap.children  //位置变化 所有 运动项
			
			switch(this.settings.moveWay){
				case 'opacity':   //如果走的是透明度，需要设置透明度与transition
					for(var i=0; i<this.opacityItem.length; i++){
						this.opacityItem[i].style.opacity = 0
						this.opacityItem[i].style.transition = ".3s opacity"
					}
					this.opacityItem[0].style.opacity = 1
					break
				case 'position':  //如果走的是位置,需要设置父级的宽度
				  //这里需要注意一下，一定要加上元素的margin
					var leftMargin = parseInt(getComputedStyle(this.positionItem[0]).marginLeft)
					var rightMargin = parseInt(getComputedStyle(this.positionItem[0]).marginRight)
					//一个位置变化 元素的实际宽度
					this.singleWidth = leftMargin + this.positionItem[0].offsetWidth + rightMargin
					//如果运动是循环的，需要复制一份内容
					if(this.settings.loop){
						this.positionItemWrap.innerHTML += this.positionItemWrap.innerHTML
					}
					//复制内容后才能设置宽度
					this.positionItemWrap.style.width = this.singleWidth * this.positionItem.length + 'px'
			}
			
			//启动自动轮播
			if(this.settings.autoplay){
				this.autoPlay()
			}
		},
		
		//透明度运动方式
		opacityMove: function(){
			
			//上一页到头
			if(this.cn<0){
				//是否循环
				if(this.settings.loop){
					//循环
					this.cn = this.endNum -1
				}else{
					//不循环
					this.cn = 0
					//解决点击头—张或者最后一张后,不能再次点击。
					//是因为canClick是在transitionend里面设置的，如果不循环的话就会停在最后。
					//再次点击的时候transitionend就不会发生，所以canclick的值就不会改变
					this.canClick = true  
				}
			}
			
			//下一页到头
			if(this.cn>this.endNum -1){
				//是否循环
				if(this.settings.loop){
					//循环
					this.cn = 0
				}else{
					//不循环
					this.cn = this.endNum -1
					this.canClick = true 
				}
			}
			
			var _this = this
			this.opacityItem[this.ln].style.opacity = 0  //将上一个运动项的透明度设置为0
			this.circles[this.ln].className = ""  //将上一个指示点的激活样式去掉
			
			this.opacityItem[this.cn].style.opacity = 1  //将当前运动项的透明度设置为1
			this.circles[this.cn].className = "active"  //将当前指示点的激活样式加上
			
			var en = 0
			yx.addEvent(this.opacityItem[this.cn], 'transitionend', function(){
				en ++
				if(en === 1){
					//注意：这里不能写成this.canClick = true，因为回调函数是节点对象调用的，this就不是指向轮播图实例对象了
					_this.canClick = true
					_this.ln = _this.cn
					
					//执行自定义事件
					_this.endFn()
				}
			})
		},
		
		//位置运动方式
		positionMove: function(){
			var _this = this
			
			//左边到头
			if(this.cn < 0){
				if(this.settings.loop){
					//循环
					/* 
					在这里需要做两件事情
					1、先让运动的父级的位置到中间，为了往右走不会出现空白
					2、同时需要修改索引值(到了中间了，并不是停在那了，而是要运动出前一排，所以cn
					的值要减个1，为了就是能运动)
					 */
					this.positionItemWrap.style.left = -this.positionItemWrap.offsetWidth/2 + "px"
					this.cn = this.endNum - 1
				}else{
					//不循环
					this.cn = 0
				}
			}
			
			//右边到头
			if(this.cn > this.endNum-1){
				if(this.settings.loop){
					//循环 则不要做任何事件，需要在运动结束后去做条件判断。
				}else{
					//不循环 则停留不动
					this.cn = this.endNum -1 
				}
			}
			
			//不循环时 才显示 指示圆点(这部分没有写css样式，了解即可)
			/* if(!this.settings.loop){
				this.circles[this.ln].className = ""  //上一个 激活样式 去掉
				this.circles[this.cn].className = "active"  //当前  激活样式 加上
			} */
			
			//运动
			// left的值 = 一个元素的宽度 * 当前cn的值 * 一次运动元素的个数
			move(
				this.positionItemWrap, 
				{ left: -this.cn*this.singleWidth*this.settings.moveNum }, 
				2000, 
				'linear', 
				function(){
					
					//当走到第二份的第一屏的时候就需要让运动的父级的left值瞬间变成0
					if(_this.cn === _this.endNum){
						_this.positionItemWrap.style.left = 0
						_this.cn = 0
					}
					
					_this.canClick = true
					_this.ln = _this.cn
					
					//执行自定义事件
					_this.endFn()
				}
			)
			
		},
		
		//上一个按钮 点击功能
		prev: function(){
			//运动中不能再次点击
			if(!this.canClick){
				return
			}
			this.canClick = false
			
			this.cn --
			this[this.settings.moveWay+"Move"]()
		},
		
		//下一个按钮 点击功能
		next: function(){
			if(!this.canClick){
				return
			}
			this.canClick = false
			
			this.cn ++
			this[this.settings.moveWay+"Move"]()
		},
		
		//自动播放功能
		autoPlay: function(){
			var _this = this
			this.timer = setInterval(function(){
				_this.next()
			}, this.settings.intervalTime)
			this.box.onmouseenter = function(){
				clearInterval(_this.timer)
				_this.timer = null
			}
			this.box.onmouseleave = function(){
				_this.autoPlay()
			}
		},
		
		//添加 自定义事件
		on: function(type, listener){  //type 事件类型，listener 回调函数
			this.events = this.events || {}
			this.events[type] = this.events[type] || []
			this.events[type].push(listener)
		},
		
		//执行 自定义事件
		trigger: function(type){  //type 事件类型
			//因为有的组件有自定义事件，有的没有。
			//所以需要做一个判断，只有有调用自定义事件的实例才能执行下面的代码
			if(this.events && this.events[type]){
				for(var i=0; i<this.events[type].length; i++){
					this.events[type][i].call(this)
				}
			}
		},
		
		endFn: function(){
			//统一添加自定义事件的函数, 要在运动完成以后添加。并且只需要加给不循环的运动
			if(!this.settings.loop){
				if(this.cn === 0){  //左边到头
					this.trigger("leftEnd")
				}
				if(this.cn === this.endNum-1){  //右边到头
					this.trigger("rightEnd")
				}
			}
		},
		
	}
	
	window.Carousel = Carousel
})(window, undefined);


